﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using MLO;
using System.Data;
using CommonLib;
using Constructor;
using Constructor.Forms;
using Constructor.Frames;

namespace MLO
{
    class MLO
    {
        public static void Start(bool showReasoning)
        {
            MLOSource.Initialize();

            TreeNode reasoningTV = new TreeNode();
            External.ExitMLO = false;
            //обходим все ситуации нижнего уровня (1 шаг)
            for (int step = 0; step < 1 && !External.ExitMLO; step++)
            {
                TreeNode StepInfo = null;
                if (showReasoning) StepInfo = reasoningTV.Nodes.Add("Шаг " + step.ToString());

                var bindedSubframeSets = new List<List<MLOSource.FrameSlot>>();
                foreach (var activeFrame in MLOSource.ActiveSituations)
                {
                    //привязываем всевозможные комбинации субфреймов
                    {
                        List<Slot> subFrameSlots = activeFrame.GetSlots(SlotType.SubFrame, true);
                        bindedSubframeSets.Clear();
                        bindedSubframeSets = MLOSource.GetBindSubframesList(subFrameSlots);
                    }
                    if (bindedSubframeSets.Count == 0) continue;

                    TreeNode SituationInfo = null;
                    if (showReasoning)
                    {
                        SituationInfo = StepInfo.Nodes.Add("Ситуация " + activeFrame.Name);
                        foreach (var set in bindedSubframeSets)
                        {
                            TreeNode SituationSetInfo = null;
                            SituationSetInfo = SituationInfo.Nodes.Add("Набор " + bindedSubframeSets.IndexOf(set) + 1);
                            foreach (var pair in set)
                            {
                                TreeNode SetPairInfo = SituationSetInfo.Nodes.Add(pair.Frame.Name + " в " + pair.Slot.Name);
                                SetPairInfo.Tag = SharedFuncs.GetSlotStringInfo(pair.Slot) +
                                    SharedFuncs.GetFrameStringInfo(pair.Frame);
                            }
                        }
                    }

                    for (int i = bindedSubframeSets.Count - 1; i >= 0; i--)
                    {
                        var set = bindedSubframeSets[i];
                        bool still_binded = true;
                        /*foreach (MLOSource.FrameSlot fs in lst)
                        {
                            if (fs.Slot.Subframe.Type == FrameType.Prototype)
                                still_binded = still_binded &&
                                     MLOSource.BindSubFrames(MLOSource.all_frames.Find(o => o.Name == fs.Slot.Subframe.Name).Name).Contains(fs.Frame);
                            else
                            {
                                List<Frame> sb_stnns = MLOSource.BindSubFrames(MLOSource.all_frames.Find(o => o.Name == fs.Slot.Subframe.Name).Name);
                                still_binded = false;
                                foreach (Frame sb_frm in sb_stnns)
                                {
                                    bool sb = true;
                                    foreach (Slot slt in sb_frm.GetSlots(SlotType.SubFrame, true))
                                    {
                                        Slot find_slt = fs.Frame.SearchInAllSlot(slt.Name);
                                        sb = find_slt != null && slt.Subframe == find_slt.Subframe;
                                    }
                                    still_binded = still_binded || sb;
                                }
                            }
                        }*/
                        if (!still_binded)
                        {
                            SituationInfo.Nodes.Add("Набор " + i + " оказался в конфликте");
                            bindedSubframeSets.RemoveAt(i);
                            continue;
                        }

                        Frame situationFrame = (Frame)activeFrame.Clone();
                        for (int fsn = 0; fsn < set.Count; fsn++)
                            situationFrame.SearchInAllSlot(set[fsn].Slot.Name).Subframe = set[fsn].Frame;
                        bool add = true;
                        List<Slot> gs = situationFrame.GetSlotsForProductions();
                        int current_slt_ind = 0;
                        for (int slt_ind = 0; slt_ind < gs.Count && add; slt_ind++)
                        {
                            current_slt_ind = slt_ind;
                            Slot prttp_slt = gs[slt_ind];
                            if (prttp_slt.Type == SlotType.Production)
                            {
                                string split = prttp_slt.Production.Item.Text;
                                Slot changing = MLOSource.GetSlotBySplit(split.Substring(split.IndexOf('.') + 1)
                                                , situationFrame);
                                if (prttp_slt.Production.isProc)
                                {
                                    List<NewItem> proc_params = new List<NewItem>();
                                    foreach (NewItem itm in prttp_slt.Production.Procedure.Params)
                                    {
                                        proc_params.Add(itm.Clone());
                                        NewItem new_item = proc_params[proc_params.Count - 1];
                                        string[] parts = new_item.Text.Split('.');
                                        new_item.Content.Subframe = situationFrame;
                                        for (int k = 1; k < parts.Length; k++)
                                            new_item.Content.Subframe = new_item.Content.Subframe.SearchInAllSlot(parts[k]).Subframe;
                                    }
                                    int procRes = MLOSource.ProcessProcedure(prttp_slt.Production.Procedure.Method.Name, proc_params);
                                    if (prttp_slt.Production.Marker)
                                        add = add && MLOSource.CompareOperation(double.Parse(changing.Default.ToString()), prttp_slt.Production.Operation, (double)procRes);
                                    else
                                        changing.Default = changing.Domain.GetValueInRange(MLOSource.DigitOperation(double.Parse(changing.Default.ToString()), prttp_slt.Production.Operation, (double)procRes));
                                }
                                else
                                {
                                    split = prttp_slt.Production.Value.Text;
                                    switch (prttp_slt.Production.Type)
                                    {
                                        case CommonLib.ValueType.Int:
                                        case CommonLib.ValueType.IntVar:
                                        case CommonLib.ValueType.Enum:
                                            {
                                                object changer_val = null;
                                                if (changing.Domain.Contains(split))
                                                    changer_val = split;
                                                else
                                                {
                                                    Slot changer = MLOSource.GetSlotBySplit(split.Substring(split.IndexOf('.') + 1)
                                                        , situationFrame);
                                                    changer_val = changer.Default;
                                                }
                                                if (prttp_slt.Production.Type == CommonLib.ValueType.Enum)
                                                {
                                                    if (prttp_slt.Production.Marker)
                                                    {
                                                        if (prttp_slt.Production.Operation == "=")
                                                            add = add && changing.Default.ToString() == changer_val.ToString();
                                                        else
                                                            add = add && changing.Default.ToString() != changer_val.ToString();
                                                    }
                                                    else
                                                        changing.Default = changer_val;
                                                }
                                                else
                                                {
                                                    if (prttp_slt.Production.Marker)
                                                        add = add && MLOSource.CompareOperation(double.Parse(changing.Default.ToString()), prttp_slt.Production.Operation, double.Parse(changer_val.ToString()));
                                                    else
                                                        changing.Default = changing.Domain.GetValueInRange(MLOSource.DigitOperation(double.Parse(changing.Default.ToString()), prttp_slt.Production.Operation, double.Parse(changer_val.ToString())));
                                                }
                                            }
                                            break;
                                        case CommonLib.ValueType.Frame:
                                            {
                                                Slot changer = MLOSource.GetSlotBySplit(split.Substring(split.IndexOf('.') + 1)
                                                    , situationFrame);
                                                if (prttp_slt.Production.Marker)
                                                {
                                                    if (prttp_slt.Production.Operation == "=")
                                                        add = add && changing.Subframe == changer.Subframe;
                                                    else
                                                        add = add && changing.Subframe != changer.Subframe;
                                                }
                                                else
                                                    changing.Subframe = changer.Subframe;
                                                break;
                                            }
                                    }
                                }
                            }
                        }
                        if (!add && showReasoning)
                        {
                            SituationInfo.Nodes[i].ForeColor = System.Drawing.Color.Red;
                            Slot errorSlot = gs[current_slt_ind];
                            try
                            {
                                if (errorSlot.Production != null)
                                    if (!errorSlot.Production.isProc)
                                        SituationInfo.Nodes[i].Tag = "Не выполнилось условие: " + errorSlot.Production.Item.Text + errorSlot.Production.Operation + errorSlot.Production.Value;
                                    else
                                        SituationInfo.Nodes[i].Tag = "Не выполнилось условие: " + errorSlot.Production.Procedure.Text;
                            }
                            catch { }
                        }
                    }
                }
                if (MLOSource.DeletionExemplars.Count > 0)
                {
                    foreach (var delExemplar in MLOSource.DeletionExemplars)
                        MLOSource.Exemplars.Remove(delExemplar);
                    MLOSource.DeletionExemplars.Clear();
                }
            }

            if (showReasoning)
            {
                Reasoning reasoningForm = new Reasoning();
                reasoningForm.treeViewAll.Nodes.Add(reasoningTV);
                TreeNode bindedSituations = reasoningTV.Clone() as TreeNode;
                foreach (TreeNode stepNode in bindedSituations.Nodes)
                {
                    for (int j = stepNode.Nodes.Count - 1; j >= 0; j--)
                    {
                        TreeNode SituationNode = stepNode.Nodes[j];
                        for (int i = SituationNode.Nodes.Count - 1; i >= 0; i--)
                        {
                            if (SituationNode.Nodes[i].ForeColor == System.Drawing.Color.Red)
                                SituationNode.Nodes[i].Remove();
                        }
                        if (SituationNode.Nodes.Count == 0)
                            SituationNode.Remove();
                    }
                }
                reasoningForm.treeViewBinded.Nodes.Add(bindedSituations);
                reasoningForm.Show();
            }
        }
    }
}
